K=kernel
U=user

OBJS = \
  $K/entry.o \
  $K/start.o \
  $K/console.o \
  $K/printf.o \
  $K/uart.o \
  $K/main.o \
  $K/proc.o \
  $K/trap.o \
  $K/kernelvec.o

  # riscv64-unknown-elf- or riscv64-linux-gnu-
  # perhaps in /opt/riscv/bin
  #TOOLPREFIX =

  # Try to infer the correct TOOLPREFIX if not set
  ifndef TOOLPREFIX
  TOOLPREFIX := $(shell if riscv64-unknown-elf-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-unknown-elf-'; \
	elif riscv64-elf-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-elf-'; \
	elif riscv64-linux-gnu-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-linux-gnu-'; \
	elif riscv64-unknown-linux-gnu-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-unknown-linux-gnu-'; \
	else echo "***" 1>&2; \
	echo "*** Error: Couldn't find a riscv64 version of GCC/binutils." 1>&2; \
	echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \
	echo "***" 1>&2; exit 1; fi)
  endif

  QEMU = qemu-system-riscv64
  MIN_QEMU_VERSION = 7.2

  CC = $(TOOLPREFIX)gcc
  AS = $(TOOLPREFIX)gas
  LD = $(TOOLPREFIX)ld
  OBJCOPY = $(TOOLPREFIX)objcopy
  OBJDUMP = $(TOOLPREFIX)objdump

  CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb -gdwarf-5
  CFLAGS += -MD
  CFLAGS += -mcmodel=medany
  CFLAGS += -ffreestanding
  CFLAGS += -fno-common -nostdlib
  CFLAGS += -fno-builtin-strncpy -fno-builtin-strncmp -fno-builtin-strlen -fno-builtin-memset
  CFLAGS += -fno-builtin-memmove -fno-builtin-memcmp -fno-builtin-log -fno-builtin-bzero
  CFLAGS += -fno-builtin-strchr -fno-builtin-exit -fno-builtin-malloc -fno-builtin-putc
  CFLAGS += -fno-builtin-free
  CFLAGS += -fno-builtin-memcpy -Wno-main
  CFLAGS += -fno-builtin-printf -fno-builtin-fprintf -fno-builtin-vprintf
  CFLAGS += -I.
  CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)

  # Disable PIE when possible (for Ubuntu 16.10 toolchain)
  ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
  CFLAGS += -fno-pie -no-pie
  endif
  ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]nopie'),)
  CFLAGS += -fno-pie -nopie
  endif

  LDFLAGS = -z max-page-size=4096

  $K/kernel: $(OBJS) $K/kernel.ld
	$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) # 指定kernel/kernel.ld为链接脚本，将目标文件进行链接，输出可执行文件kernel/kernel
	$(OBJDUMP) -S $K/kernel > $K/kernel.asm # 将 kernel 可执行文件反汇编出来，并将其保存在kernel/kernel.asm中
	$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym # 将kernel 符号表入口地址打印到 kernel/kernel.sym 中

  $K/%.o: $K/%.S
	$(CC) -g -c -o $@ $<

clean:
	rm -f */*.o */*.d */*.asm */*.sym \
	$K/kernel .gdbinit

# try to generate a unique GDB port
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
# QEMU's gdb stub command line changed in 0.11
QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \
	then echo "-gdb tcp::$(GDBPORT)"; \
	else echo "-s -p $(GDBPORT)"; fi)
ifndef CPUS
CPUS := 3
endif

QEMUOPTS = -machine virt -bios none -kernel $K/kernel -m 128M -smp $(CPUS) -nographic
QEMUOPTS += -global virtio-mmio.force-legacy=false

qemu: check-qemu-version $K/kernel
	$(QEMU) $(QEMUOPTS)

.gdbinit: .gdbinit.tmpl-riscv
	sed "s/:1234/:$(GDBPORT)/" < $^ > $@

qemu-gdb: $K/kernel .gdbinit
	@echo "*** Now run 'gdb' in another window." 1>&2
	$(QEMU) $(QEMUOPTS) -S $(QEMUGDB)

QEMU_VERSION := $(shell $(QEMU) --version | head -n 1 | sed -E 's/^QEMU emulator version ([0-9]+\.[0-9]+)\..*/\1/')
check-qemu-version:
	@if [ "$(shell echo "$(QEMU_VERSION) >= $(MIN_QEMU_VERSION)" | bc)" -eq 0 ]; then \
		echo "ERROR: Need qemu version >= $(MIN_QEMU_VERSION)"; \
		exit 1; \
	fi
